import numpy as np
import matplotlib.pyplot as plt
import ast
filename="nn_data/data1.txt"
data=[]
raw_data=[]
with open(filename) as file:
    for line in file:
        a_data=line.replace(',',' ').split()
        score1=ast.literal_eval(a_data[0])
        score2=ast.literal_eval(a_data[1])
        label=int(a_data[2])
        data.append([score1/100,score2/100,label])
        raw_data.append([score1,score2,label])
      
    data=np.array(data)  
    raw_data=np.array(raw_data)
    # print(data)
#决策边界
def boundary(x1,w):
    return [-(x*w[0]+100*w[2])/w[1] for x in x1]
#激活函数
def sigmoid(x):
    return 1/(1+np.exp(-x))
#预测
def prediction(x):
    if x>=0.5:
        return 1
    else:
        return 0
#定义一个神经网络类
class nn:
    def __init__(self,data,batch_size,lr,train_count):
        self.data=data
        self.batch_size=batch_size
        self.lr=lr
        self.train_count=train_count
        self.w=np.zeros(3)#参数初始化为0
        
    def Calculate1(self,data):
        m=len(data)
        acc=[]
        loss=0
        dw=np.zeros(3)
        for i in range(len(data)):
            x1,x2,label=data[i]
            x_=np.array([x1,x2,1])
            y=sigmoid(np.dot(self.w,x_))
            acc.append(prediction(y)==label)
            loss+=((label-y)**2)/m
            dw+=2*(y-label)*y*(1-y)*x_
            
        self.w-=dw*self.lr/m
        return acc,loss 
    
    def Train(self):
        Accuracy=[]
        Loss=[]
        for i in range(self.train_count):
            np.random.shuffle(self.data)
            for j in range(len(self.data)//self.batch_size):
                train_data=self.data[j*self.batch_size:(j+1)*self.batch_size:1]
                acc,loss=self.Calculate1(train_data)
                accuracy=acc.count(1)*100/len(train_data)
                if j==0:
                    Loss.append(loss)
                    Accuracy.append(accuracy)
                    print(f"The {i+1} epoch: Acc is {accuracy}% Loss is {loss}")
    
        return Accuracy,Loss,self.w

if __name__=="__main__" :
    test=nn(data,20,0.01,5000)
    Accuracy,Loss,w=test.Train()
    # 创建画布和子图
    print("Last w is:",w)
    fig,ax=plt.subplots(1,3,figsize=(12,4))
    s1=np.array([i for i in range(101)])
    s2=boundary(s1,w)
    ax[0].plot([i+1 for i in range(5000)],Accuracy)
    ax[0].set_xlabel("Epoch")
    ax[0].set_ylabel("Acc")
    ax[1].plot([i+1 for i in range(5000)],Loss)
    ax[1].set_xlabel("Epoch")
    ax[1].set_ylabel("Loss")
    labels=raw_data[:, 2]
    colors=['r' if k==1 else 'g' for k in labels]
    ax[2].scatter(raw_data[:, 0],raw_data[:, 1],c=colors)
    ax[2].set_xlabel("x1")
    ax[2].set_ylabel("x2")
    ax[2].plot(s1,s2,c='b')
    # 调整子图间的间距
    plt.tight_layout()
    plt.show()